package cc.rengu.redp.system.service.impl;

import cc.rengu.redp.common.exception.RedpException;
import cc.rengu.redp.common.utils.DateUtil;
import cc.rengu.redp.common.utils.RedpUtil;
import cc.rengu.redp.common.utils.TreeUtil;
import cc.rengu.redp.system.dao.OrganizationMapper;
import cc.rengu.redp.system.domain.Organization;
import cc.rengu.redp.system.domain.OrganizationTree;
import cc.rengu.redp.system.domain.OrganizationVO;
import cc.rengu.redp.system.service.OrganizationService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author System
 */
@Slf4j
@Service
public class OrganizationServiceImpl extends ServiceImpl<OrganizationMapper, Organization> implements OrganizationService {

    @Override
    public Map<String, Object> findOrgTrees(OrganizationVO organization) {
        Map<String, Object> result = new HashMap<>();
        try {
            LambdaQueryWrapper<Organization> queryWrapper = new LambdaQueryWrapper<>();
            findCondition(queryWrapper, organization);
            List<Organization> organizations = baseMapper.selectList(queryWrapper);

            List<OrganizationTree> trees = new ArrayList<>();
            List<String> ids = new ArrayList<>();
            Map<String, String> idToCode = new LinkedHashMap<>();
            buildTrees(trees, organizations, ids, idToCode);

            result.put("ids", ids);
            result.put("idToCode", idToCode);
            OrganizationTree orgTree = TreeUtil.build(trees, new OrganizationTree());
            result.put("rows", orgTree);

            result.put("total", organizations.size());
        } catch (NumberFormatException e) {
            log.error("查询机构失败", e);
            result.put("rows", null);
            result.put("total", 0);
        }
        return result;
    }

    private void buildTrees(List<OrganizationTree> trees, List<Organization> organizations, List<String> ids, Map<String, String> idToCode) {
        organizations.forEach(organization -> {
            ids.add(organization.getId().toString());
            idToCode.put(organization.getId().toString(), organization.getOrgCode());
            OrganizationTree tree = new OrganizationTree();
            tree.setId(organization.getId().toString());
            tree.setKey(tree.getId());
            tree.setParentId(organization.getParentOrgId() == null ? null : organization.getParentOrgId().toString());
            tree.setText(organization.getOrgName());
            tree.setValue(tree.getId());
            tree.setTitle(tree.getText());
            tree.setCreateTime(DateUtil.localDateTimeToDate(organization.getCreateTime()));
            tree.setModifyTime(DateUtil.localDateTimeToDate(organization.getModifyTime()));
            tree.setOrder((double) ids.size());
            tree.setTitle(tree.getText());
            tree.setTenantId(organization.getTenantId());
            tree.setOrgName(organization.getOrgName());
            tree.setOrgType(organization.getOrgType());
            tree.setOrgCode(organization.getOrgCode());
            tree.setOrgLevel(organization.getOrgLevel());
            tree.setParentOrgCode(organization.getParentOrgCode());

            trees.add(tree);
        });
    }

    private void findCondition(LambdaQueryWrapper<Organization> queryWrapper, OrganizationVO organization) {
        if (StringUtils.isNotBlank(organization.getTenantId())) {
            queryWrapper.eq(Organization::getTenantId, organization.getTenantId());
        }
        if (StringUtils.isNotBlank(organization.getOrgCode())) {
            queryWrapper.eq(Organization::getOrgCode, organization.getOrgCode());
        }
        if (StringUtils.isNotBlank(organization.getOrgName())) {
            queryWrapper.eq(Organization::getOrgName, organization.getOrgName());
        }
        if (StringUtils.isNotBlank(organization.getOrgType())) {
            queryWrapper.eq(Organization::getOrgType, organization.getOrgType());
        }
        if (StringUtils.isNotBlank(organization.getParentOrgCode())) {
            queryWrapper.eq(Organization::getParentOrgCode, organization.getParentOrgCode());
        }
        if (StringUtils.isNotBlank(organization.getParentOrgId())) {
            queryWrapper.eq(Organization::getParentOrgId, organization.getParentOrgId());
        }
    }

    @Override
    public void add(OrganizationVO organization) throws RedpException {
        Organization newOrg = new Organization();
        if (!checkOrgCodeDuplication(organization.getTenantId(), organization.getOrgCode())) {
            throw new RedpException("机构编码已存在");
        }
        BeanUtils.copyProperties(organization, newOrg);
        if (StringUtils.isNotBlank(organization.getParentOrgId())) {
            newOrg.setParentOrgId(Long.valueOf(organization.getParentOrgId()));
            //生成机构链
            newOrg.setOrgChain(generateOrgChain(organization.getOrgCode(), newOrg.getParentOrgId()));
            if (StringUtils.isBlank(newOrg.getOrgChain())) {
                throw new RedpException("机构链生成失败");
            }
        } else {
            newOrg.setOrgChain(organization.getOrgCode());
        }
        newOrg.setCreateBy(RedpUtil.getCurrentUser().getUsername());
        newOrg.setCrtOrgId(RedpUtil.getCurrentUser().getOrgCode());
        newOrg.setCreateTime(LocalDateTime.now());
        newOrg.setOrgName(organization.getOrgName().trim());
        newOrg.setModifyBy(newOrg.getCreateBy());
        newOrg.setModifyTime(LocalDateTime.now());
        this.save(newOrg);
    }

    @Override
    public void update(OrganizationVO organization) throws RedpException {
        Organization db = baseMapper.selectById(Long.valueOf(organization.getId()));
        BeanUtils.copyProperties(organization, db);
        if (StringUtils.isNotBlank(organization.getParentOrgId())) {
            db.setParentOrgId(Long.valueOf(organization.getParentOrgId()));
            //生成机构链
            db.setOrgChain(generateOrgChain(organization.getOrgCode(), db.getParentOrgId()));
            if (StringUtils.isBlank(db.getOrgChain())) {
                throw new RedpException("机构链生成失败");
            }
        } else {
            db.setOrgChain(organization.getOrgCode());
        }
        db.setModifyTime(LocalDateTime.now());
        db.setModifyBy(RedpUtil.getCurrentUser().getUsername());
        baseMapper.updateById(db);
    }

    @Override
    public void delete(Long[] orgIds) throws Exception {
        for (Long orgId : orgIds) {
            Organization db = this.baseMapper.selectById(orgId);
            db.setModifyTime(LocalDateTime.now());
            db.setModifyBy(RedpUtil.getCurrentUser().getUsername());
            db.setOrgStatus(Organization.STATUS_CANCELED);
            this.baseMapper.updateById(db);
            LambdaQueryWrapper<Organization> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Organization::getParentOrgId, orgId);
            List<Organization> organizations = baseMapper.selectList(queryWrapper);
            List<Long> subOrgIds = organizations.stream().map(i -> i.getId()).collect(Collectors.toList());
            // 递归删除下级机构
            this.delete(subOrgIds.toArray(new Long[subOrgIds.size()]));
        }
    }

    @Override
    public List<Organization> findList(OrganizationVO organization) {
        LambdaQueryWrapper<Organization> queryWrapper = new LambdaQueryWrapper<>();
        findCondition(queryWrapper, organization);
        queryWrapper.orderByAsc(Organization::getCreateTime);
        return this.baseMapper.selectList(queryWrapper);
    }

    /**
     * 生成机构链，表示总行与当前机构之间的级联关系
     * @param currentOrgCode
     * @param parentOrgId
     * @return
     */
    private String generateOrgChain(String currentOrgCode, Long parentOrgId) {
        Organization parentOrg = this.baseMapper.selectById(parentOrgId);
        if (parentOrg == null) {
            return null;
        }

        return new StringBuilder().append(parentOrg.getOrgChain()).append(StringPool.COLON).append(currentOrgCode).toString();
    }

    /**
     * 检查机构编号是否重复
     * @param tenantId
     * @param orgCode
     * @return
     */
    private boolean checkOrgCodeDuplication(String tenantId, String orgCode) {
        LambdaQueryWrapper<Organization> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(Organization::getTenantId, tenantId).eq(Organization::getOrgCode, orgCode);
        Organization exist = this.getOne(lambdaQueryWrapper);
        if (exist != null) {
            return false;
        } else {
            return true;
        }
    }
}
